#include "../pch.h"
#include "REFEncoding.h"
#include "REFLatin1Encoding.h"

namespace BFX
{

// We only use the best-fit table, of which ASCII is a superset for us.
REFLatin1Encoding::REFLatin1Encoding() : REFEncoding(REFEncoding::ISO_8859_1)
{
}


REFLatin1Encoding::~REFLatin1Encoding()
{
}

// Calculates the maximum number of bytes produced by encoding the specified number of characters.
int REFLatin1Encoding::GetMaxByteCount(int nCharCount) const
{
	BFX_REQUIRE (nCharCount >= 0 && "Non-negative number required.");

	// Characters would be # of characters + 1 in case high surrogate is ? * max fallback
	long long lByteCount = (long long)nCharCount + 1;

	BFX_ENSURE1 (lByteCount <= 0x7fffffff, "Too many characters. The resulting number of bytes is larger than what can be returned as an int.");
	return (int)lByteCount;
}

// Calculates the maximum number of characters produced by decoding the specified number of bytes.
int REFLatin1Encoding::GetMaxCharCount(int nByteCount) const
{
	BFX_REQUIRE (nByteCount >= 0 && "Non-negative number required.");

	// Just return length, SBCS stay the same length because they don't map to surrogate
	long long lCharCount = (long long)nByteCount;

	BFX_ENSURE1 (lCharCount <= 0x7fffffff, "Too many characters. The resulting number of bytes is larger than what can be returned as an int.");

	return (int)lCharCount;
}

// Calculates the number of characters produced by decoding a sequence of bytes.
int REFLatin1Encoding::GetCharCount(const BYTE* pBytes, int nCount, REFDecoder* pDecoder) const
{
	BFX_REQUIRE (pBytes != NULL && nCount >= 0);

	// Just return length, SBCS stay the same length because they don't map to surrogate 
	// pairs and we don't have to fallback because all latin1Encoding code points are unicode
	return nCount;
}

// Decodes a sequence of bytes into a set of characters.
int REFLatin1Encoding::GetChars(const BYTE* pBytes, int nByteCount, OUT UCHAR* pChars, int nCharCount, REFDecoder* pDecoder) const
{
	BFX_REQUIRE(pBytes != NULL && nByteCount >= 0);
	BFX_ASSERT(pChars != NULL && nCharCount >= 0);

	// Need byteCount chars, otherwise too small buffer
	if (nCharCount < nByteCount)
	{ 
		// Buffer too small.  Do we throw?
		BFX_ENSURE(nCharCount >= 1);

		// Don't throw, correct buffer size
		nByteCount = nCharCount;
	}

	// Do it our fast way
	const BYTE* byteEnd = pBytes + nByteCount; 

	// Quick loop, all bytes are the same as chars, so no fallbacks for latin1 
	while (pBytes < byteEnd) 
	{
		*(pChars) = (UCHAR)*(pBytes);
		pChars++;
		pBytes++;
	}

	// Converted sequence is same length as input, so output charsUsed is same as byteCount; 
	return nByteCount;
}

// Calculates the number of bytes produced by encoding a set of characters.
int REFLatin1Encoding::GetByteCount(const UCHAR* pChars, int nCharCount) const
{
	BFX_REQUIRE(nCharCount >= 0 && pChars != NULL);

	// Count is more complicated if you have a funky fallback
	// For fallback we may need a fallback buffer, we know we're not default fallback 
	int nByteCount = 0; 

	// Start by assuming default count, then +/- for fallback characters 
	const UCHAR* pCharEnd = pChars + nCharCount;

	// For fallback.
	bool bFallingBack = false;

	// Go ahead and do it, including the fallback.
	UCHAR ch; 
	while ((ch = bFallingBack ? '?' : '\0') != 0 || pChars < pCharEnd)
	{
		bFallingBack = false;

		// First unwind any fallback
		if (ch == 0)
		{
			// No fallback, just get next char 
			ch = *pChars;
			pChars++;
		} 

		// Check for fallback, this'll catch surrogate pairs too. 
		// no chars >= 0x100 are allowed.
		if (ch > 0xff)
		{
			// Get Fallback
			bFallingBack = true;
			pChars ++;

			continue; 
		}

		// We'll use this one
		nByteCount++;
	}

	return nByteCount;
}

// Encodes a set of characters into a sequence of bytes.
int REFLatin1Encoding::GetBytes(const UCHAR* pChars, int nCharCount, OUT BYTE* pBytes, int nByteCount) const
{
	BFX_REQUIRE(pBytes != NULL && nByteCount >= 0);
	BFX_REQUIRE(pChars != NULL && nCharCount >= 0);

	// prepare our end 
	const UCHAR* pCharEnd = pChars + nCharCount;
	BYTE* pByteStart = pBytes; 
	const UCHAR* pCharStart = pChars;

	// TODO: fast version for replacement fallback.

	// Slower version, have to do real fallback.

	// prepare our end 
	BYTE* pByteEnd = pBytes + nByteCount;

	// For fallback
	bool bFallingBack = false;

	// Now we may have fallback char[] already from the encoder fallback above 

	// Go ahead and do it, including the fallback. 
	UCHAR ch;
	while ((ch = bFallingBack ? '?' : '\0') != 0 || pChars < pCharEnd)
	{
		bFallingBack = false;

		// First unwind any fallback
		if (ch == 0) 
		{ 
			// No fallback, just get next char
			ch = *pChars; 
			pChars++;
		}

		// Check for fallback, this'll catch surrogate pairs too. 
		// All characters >= 0x100 must fall back.
		if (ch > 0xff) 
		{ 
			// Get Fallback 
			bFallingBack = true;
			pChars++;

			continue;
		}

		// We'll use this one 
		// Bounds check
		if (pBytes >= pByteEnd) 
		{ 
			// didn't use this char, we'll throw or use buffer
			BFX_ASSERT(!bFallingBack);

			BFX_ENSURE (pChars != pCharStart);						// throw ?
			break;                                              // don't throw, stop 
		}

		// Go ahead and add it
		*pBytes = (BYTE)ch;
		pBytes++;
	} 

	return (int)(pBytes - pByteStart);
}

}	//	namespace BFX
